﻿using IdentityModel.Client;
using System.IdentityModel.Tokens.Jwt;

namespace BlzOidc.Data
{
    /// <summary>
    /// Access Token管理器
    /// </summary>
    public class TokenManager
    {
        private readonly HttpClient _httpClient;
        private readonly TokenProvider _tokenProvider;

        public TokenManager(HttpClient httpClient, TokenProvider tokenProvider)
        {
            _httpClient = httpClient;
            _tokenProvider = tokenProvider;
        }

        /// <summary>
        /// 获取有效的Access Token
        /// </summary>
        /// <returns></returns>
        public async Task<string> GetValidAccessTokenAsync()
        {
            //从Access Token解析得到有效期
            var _accessTokenExpire = GetExpireTimeFromAccessToken(_tokenProvider.AccessToken);

            //如果Access Token过期，更新token
            if (_accessTokenExpire < DateTime.UtcNow)
            {
                //更新token
                await RefreshTokenAsync();
            }

            return _tokenProvider.AccessToken;
        }

        //从Access Token解析得到有效期
        private DateTime GetExpireTimeFromAccessToken(string? accessToken)
        {
            if (string.IsNullOrWhiteSpace(accessToken))
                return DateTime.MinValue;

            var jwtSecurityToken = new JwtSecurityToken(accessToken);

            return jwtSecurityToken.ValidTo;
        }

        //更新token
        private async Task RefreshTokenAsync()
        {
            //发现认证服务端点
            var discoveryResponse = await _httpClient.GetDiscoveryDocumentAsync("https://localhost:5001");
            if (discoveryResponse.IsError)
            {
                throw new Exception(discoveryResponse.Error);
            }

            //根据Refresh Token请求token
            var tokenResponse = await _httpClient.RequestRefreshTokenAsync(new RefreshTokenRequest
            {
                //https://localhost:5001/connect/token
                Address = discoveryResponse.TokenEndpoint,
                ClientId = "BlazorServerOidc",
                ClientSecret = "BlazorServerOidc.Secret",
                RefreshToken = _tokenProvider.RefreshToken,
            });

            if (tokenResponse.IsError)
            {
                throw new Exception(tokenResponse.Error);
            }

            //保存新的token
            _tokenProvider.AccessToken = tokenResponse.AccessToken;
            _tokenProvider.RefreshToken = tokenResponse.RefreshToken;

            Console.WriteLine($"更新token成功,{Environment.NewLine}AccessToken={_tokenProvider.AccessToken}{Environment.NewLine}RefreshToken={_tokenProvider.RefreshToken}");
        }
    }
}
